/*
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.takahirom.materialelement.animation.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.graphics.ColorMatrixColorFilter;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.ArrayMap;
import android.widget.ImageView;
import com.github.takahirom.materialelement.animation.ObservableColorMatrix;
import java.util.ArrayList;
/**
* Utility methods for working with animations.
*/
public class AnimatorUtils {
private AnimatorUtils() {
}
/**
* https://halfthought.wordpress.com/2014/11/07/reveal-transition/
* <p/>
* Interrupting Activity transitions can yield an OperationNotSupportedException when the
* transition tries to pause the animator. Yikes! We can fix this by wrapping the Animator:
*/
public static class NoPauseAnimator extends Animator {
private final Animator mAnimator;
private final ArrayMap<AnimatorListener, AnimatorListener> mListeners = new ArrayMap<>();
public NoPauseAnimator(Animator animator) {
mAnimator = animator;
}
@Override
public void addListener(AnimatorListener listener) {
AnimatorListener wrapper = new AnimatorListenerWrapper(this, listener);
if (!mListeners.containsKey(listener)) {
mListeners.put(listener, wrapper);
mAnimator.addListener(wrapper);
}
}
@Override
public void cancel() {
mAnimator.cancel();
}
@Override
public void end() {
mAnimator.end();
}
@Override
public long getDuration() {
return mAnimator.getDuration();
}
@Override
public TimeInterpolator getInterpolator() {
return mAnimator.getInterpolator();
}
@Override
public void setInterpolator(TimeInterpolator timeInterpolator) {
mAnimator.setInterpolator(timeInterpolator);
}
@Override
public ArrayList<AnimatorListener> getListeners() {
return new ArrayList<>(mListeners.keySet());
}
@Override
public long getStartDelay() {
return mAnimator.getStartDelay();
}
@Override
public void setStartDelay(long delayMS) {
mAnimator.setStartDelay(delayMS);
}
@Override
public boolean isPaused() {
return mAnimator.isPaused();
}
@Override
public boolean isRunning() {
return mAnimator.isRunning();
}
@Override
public boolean isStarted() {
return mAnimator.isStarted();
}
/* We don't want to override pause or resume methods because we don't want them
* to affect mAnimator.
public void pause();
public void resume();
public void addPauseListener(AnimatorPauseListener listener);
public void removePauseListener(AnimatorPauseListener listener);
*/
@Override
public void removeAllListeners() {
mListeners.clear();
mAnimator.removeAllListeners();
}
@Override
public void removeListener(AnimatorListener listener) {
AnimatorListener wrapper = mListeners.get(listener);
if (wrapper != null) {
mListeners.remove(listener);
mAnimator.removeListener(wrapper);
}
}
@Override
public Animator setDuration(long durationMS) {
mAnimator.setDuration(durationMS);
return this;
}
@Override
public void setTarget(Object target) {
mAnimator.setTarget(target);
}
@Override
public void setupEndValues() {
mAnimator.setupEndValues();
}
@Override
public void setupStartValues() {
mAnimator.setupStartValues();
}
@Override
public void start() {
mAnimator.start();
}
}
private static class AnimatorListenerWrapper implements Animator.AnimatorListener {
private final Animator mAnimator;
private final Animator.AnimatorListener mListener;
AnimatorListenerWrapper(Animator animator, Animator.AnimatorListener listener) {
mAnimator = animator;
mListener = listener;
}
@Override
public void onAnimationStart(Animator animator) {
mListener.onAnimationStart(mAnimator);
}
@Override
public void onAnimationEnd(Animator animator) {
mListener.onAnimationEnd(mAnimator);
}
@Override
public void onAnimationCancel(Animator animator) {
mListener.onAnimationCancel(mAnimator);
}
@Override
public void onAnimationRepeat(Animator animator) {
mListener.onAnimationRepeat(mAnimator);
}
}
public static void startLoadingAnimation(final ImageView loadingImageImageView) {
// Alpha
loadingImageImageView.setAlpha(0F);
loadingImageImageView.animate().setDuration(1000L).alpha(1F);
// Saturation
ViewCompat.setHasTransientState(loadingImageImageView, true);
final ObservableColorMatrix cm = new ObservableColorMatrix();
ObjectAnimator saturation = ObjectAnimator.ofFloat(
cm, ObservableColorMatrix.SATURATION, 0f, 1f);
saturation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener
() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
loadingImageImageView.setColorFilter(new ColorMatrixColorFilter(cm));
}
});
saturation.setDuration(2000L);
saturation.setInterpolator(new FastOutSlowInInterpolator());
saturation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
loadingImageImageView.clearColorFilter();
ViewCompat.setHasTransientState(loadingImageImageView, false);
}
});
saturation.start();
}
}